home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 31
/
Aminet 31 (1999)(Schatztruhe)[!][Jun 1999].iso
/
Aminet
/
dev
/
c
/
vbccm68ksrc.lha
/
vbcc
/
vlink
/
linker.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-03-07
|
46KB
|
1,476 lines
/* $VER: vlink linker.c V0.6a (19.12.98)
*
* This file is part of vlink, a portable linker for multiple
* object formats.
* Copyright (c) 1997-99 Frank Wille
*
* vlink is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-99 by Volker Barthelmann.
* vlink may be freely redistributed as long as no modifications are
* made and nothing is charged for it. Non-commercial usage is allowed
* without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v0.6a (19.12.98) phx
* Endianess of linking process will be determined by the type
* of the first object.
* Support for little endian object file formats. All read/write
* operation on the object data is done in current endianess.
* v0.6 (24.10.98) phx
* Take base register section offset from FFFuncs.baseoff.
* v0.5e (05.10.98) phx
* Linking a ID_LIBARCH object requires its PriPointers to be
* added to the global list: add_priptrs().
* Call make_priptr_objects() after processing all objects in
* linker_resolve has finished. If there are entries in the Pri-
* Pointers list, then create some artificial sections (usually
* constructor and destructor lists).
* insertnode() <-> insertbehind().
* v0.5d (22.08.98) phx
* Faster memory allocation can be activated by #define FASTALLOC.
* Directories are only scanned if needed (AmigaOS filesystem is
* too slow).
* v0.5c (08.07.98) phx
* ID_ARTIFICIAL objects, i.e. objects created by the linker
* are supported.
* v0.5 (27.06.98) phx
* Target-specific linker symbol support.
* v0.4 (05.06.98) phx
* Rewrote linker_join(). Now it can be guaranteed, that first
* all code sections will be linked, then the data and finally
* the bss sections.
* Rewrote find_lnksect(). A lot more factors are now involved
* in the decision if two sections can be coalesced: relative
* references between the two, both are addressed base-relative,
* or target-specific factors.
* New functions for detection of relative references:
* addrelref(), copyrelrefs(), checkrelrefs().
* assign_common() finds a bss section for common symbols.
* v0.3b (02.05.98) phx
* There were still infinite loops, if an object comes without
* any section.
* v0.3 (16.04.98) phx
* Resolving ADDR16_HA/HI/LO references to a relocatable symbol
* didn't work (2 bytes of the next instructions were overwritten).
* Fixed print_function_name(). Didn't work, if symbols had
* a known size. Additionally, it can differentiate between
* 'no type', 'function' and 'object' now.
* Avoid infinite loops for object units without section in
* linker_join().
* v0.2 (07.03.98) phx
* Base relative relocations must not be resolved, if the output
* file is a relocatable object again. Base relative xrefs were
* even completely corrupted and overwrote the following
* instruction.
* Library units are linked immediately and are no longer always
* the last units in an output file.
* Base relative relocation didn't work for baseoff=0x8000.
* v0.1 (27.02.98) phx
* First version that seems to link AmigaOS ADOS and EHF
* objects and libraries. Many common features, like linking
* sections together which have relative references, are
* still missing. Also, PowerPC-ELF32 support is about to come.
* v0.0 (02.12.97) phx
* File created.
*/
#define LINKER_C
#include "vlink.h"
static char namebuf[FNAMEBUFSIZE];
static const char *filetypes[] = {
"unknown",
"object",
"executable",NULL,
"shared object",NULL,NULL,NULL,
"library"
};
static const char *sec_names[] = {
"undefined","code","data","bss",NULL
};
void linker_init(struct GlobalVars *);
void linker_load(struct GlobalVars *);
void linker_relrefs(struct GlobalVars *);
void linker_resolve(struct GlobalVars *);
void linker_join(struct GlobalVars *);
void linker_copy(struct GlobalVars *);
void linker_write(struct GlobalVars *);
void linker_cleanup(struct GlobalVars *);
char *getobjname(struct ObjectUnit *);
void print_function_name(struct Section *,unsigned long);
bool trace_sym_access(struct GlobalVars *,char *);
static void resolve_reloc(struct GlobalVars *,struct LinkedSection *,
struct Section *,struct Reloc *);
static void resolve_xref(struct GlobalVars *,struct LinkedSection *,
struct Section *,struct XReference *);
static void newreloc(struct LinkedSection *,struct LinkedSection *,
unsigned long,int32,uint8);
static void assign_common(struct GlobalVars *);
static char *maplibrary(struct GlobalVars *,struct InputFile *);
static char *searchlib(struct GlobalVars *,char *,int);
static char *scan_directory(char *,char *,int);
static void addrelref(struct RelRef **,struct Section *);
static void copyrelrefs(struct RelRef **,struct Section *);
static bool checkrelrefs(struct RelRef *,struct Section *);
static struct LinkedSection *create_lnksect(struct GlobalVars *,char *,
uint8,uint8,uint8,uint8);
static struct LinkedSection *find_lnksect(struct GlobalVars *,
struct Section *);
static void combine_sections(struct LinkedSection *,struct Section *,uint8);
static void print_symbol(FILE *,struct Symbol *);
static char *protstring(uint8);
void linker_init(struct GlobalVars *gv)
{
initlist(&gv->linkfiles);
initlist(&gv->selobjects);
initlist(&gv->libobjects);
initlist(&gv->sharedobjects);
gv->symbols = alloc_hashtable(SYMHTABSIZE);
initlist(&gv->pripointers);
gv->big_endian = -1;
}
void linker_load(struct GlobalVars *gv)
/* load all objects and libraries into memory, identify their */
/* format, then read all symbols and convert into internal format */
{
struct InputFile *ifn = (struct InputFile *)gv->inputlist.first;
struct InputFile *nextifn;
struct LinkFile *lf;
uint8 *objptr;
char *objname;
unsigned long objlen;
int i,ff;
if (gv->trace_file)
fprintf(gv->trace_file,"\nLoading files:\n\n");
while (nextifn = (struct InputFile *)ifn->n.next) {
if (ifn->lib) {
if (!(objptr = (uint8 *)maplibrary(gv,ifn))) {
sprintf(namebuf,"-l%s",ifn->name);
error(8,namebuf); /* cannot open -lxxx */
}
}
else {
if (objptr = (uint8 *)mapfile(ifn->name))
strcpy(namebuf,ifn->name);
else
error(8,ifn->name); /* cannot open xxx */
}
objlen = *(size_t *)(objptr - sizeof(size_t));
objname = base_name(namebuf);
/* determine the object's file format */
for (i=0,ff=ID_UNKNOWN; fff[i]; i++) {
if ((ff = (fff[i]->identify)(objname,objptr,objlen)) != ID_UNKNOWN)
break;
}
if (ff == ID_UNKNOWN)
error(11,objname); /* File format not recognized */
/* use endianess of first object read */
if (gv->big_endian < 0)
gv->big_endian = fff[i]->big_endian;
else if (gv->big_endian != fff[i]->big_endian)
error(61,objname); /* endianess differs from previous objects */
/* create new link file node */
lf = (struct LinkFile *)alloc(sizeof(struct LinkFile));
lf->pathname = allocstring(namebuf);
lf->filename = base_name(lf->pathname);
lf->data = objptr;
lf->length = objlen;
lf->format = (uint8)i;
lf->type = (uint8)ff;
if (gv->trace_file)
fprintf(gv->trace_file,"%s (%s %s)\n",namebuf,fff[i]->tname,
filetypes[ff]);
/* read the file and convert into internal format */
fff[i]->readconv(gv,lf);
addtail(&gv->linkfiles,&lf->n); /* not really needed */
ifn = nextifn; /* next input file */
}
}
void linker_resolve(struct GlobalVars *gv)
/* Resolve all symbol references and pull the required objects into */
/* the gv->selobjects list. */
{
bool priptrs_made = FALSE;
struct ObjectUnit *obj = (s